package cn.tedu.csmall.stock.webapi.controller;

import cn.tedu.csmall.commons.exception.CoolSharkServiceException;
import cn.tedu.csmall.commons.pojo.stock.dto.StockReduceCountDTO;
import cn.tedu.csmall.commons.restful.JsonResult;
import cn.tedu.csmall.commons.restful.ResponseCode;
import cn.tedu.csmall.stock.service.IStockService;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/base/stock")
@Api(tags = "库存管理模块")
public class StockController {

    @Autowired
    private IStockService stockService;

    @PostMapping("/reduce/count")
    @ApiOperation("减少库存数的功能")
    // @SentinelResource注解需要编写在控制层方法上，在该方法运行一次后，会被sentinel仪表台检测
    // 如果这个方法不运行，sentinel仪表台是无法显示这个方法的
    // 括号里"减少库存数"这个描述，会显示在仪表台上，作为当前方法的名称
    // blockHandler是注解中的属性，它可以注定当请求被限流时，自定义运动的方法名称，blockError是自定义的名称
    // fallback是注解中的属性，它可以指定当控制器方法运行发生异常时
    @SentinelResource(value = "减少库存数",
                      blockHandler = "blockError",
                      fallback = "fallbackError")
    public JsonResult reduceStock(StockReduceCountDTO stockReduceCountDTO){
        // 调用业务逻辑层方法，如果发生异常，将由全局异常处理类处理
        stockService.reduceStockCount(stockReduceCountDTO);
//        try {
//            Thread.sleep(5000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        if(Math.random()<0.5){
//            throw new CoolSharkServiceException(
//                    ResponseCode.INTERNAL_SERVER_ERROR,"随机异常");
//        }
        return JsonResult.ok("库存减少完成！");
    }
    // Sentinel自定义限流方法定义规则
    // 1.访问修饰符必须是public
    // 2.返回值类型必须和控制器方法一致
    // 3.方法名必须是和@SentinelResourse注解定义的方法名对应
    // 4.方法的参数和控制器方法参数一致，然后再额外添加一个参数BlockException表示限流异常
    public JsonResult blockError(StockReduceCountDTO stockReduceCountDTO,
                                 BlockException e){
        //这个方法运行表示当前请求被限流了，给出响应，提示该用户被限流
        return JsonResult.failed(ResponseCode.INTERNAL_SERVER_ERROR,
                "服务器忙，请稍后再试");
    }

    // 自定义降级方法定义规则和限流方法基本一致
    // 参数汇总额外的返回值类型变化为Throwable
    // 当控制器方法运行有异常时，会运行这个方法，异常对象会被Throwable接收
    //  实际开发中可以运行之前较老版本的代码，所以叫“降级”

    public JsonResult fallbackError(StockReduceCountDTO stockReduceCountDTO,
                                    Throwable throwable){

        //输出异常信息到控制台
        throwable.printStackTrace();
        //返回降级方法的运行消息
        return JsonResult.failed(
                ResponseCode.INTERNAL_SERVER_ERROR,"方法异常，服务降级");
    }

}
